using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using TouchSmart.Drawing;

namespace TouchSmart.Gestures
{
    public class EventDriver
    {
        private readonly Control _control;

        public EventDriver(Control control)
        {
            _control = control;
            _control.MouseDown += MouseDownHandler;
            _control.MouseMove += MouseMoveHandler;
            _control.MouseUp += MouseUpHandler;
        }

        #region Events

        public event EventHandler<MovementEventArgs> Movement;
        public event EventHandler<ClickEventArgs> Click;
        public event EventHandler<SlideEventArgs> Slide;
        public event EventHandler<ClickEventArgs> MouseDown;
        public event EventHandler<ClickEventArgs> MouseUp;


        protected void OnMovement(Point vector)
        {
            var local = Movement;
            if (local != null)
            {
                local(this, new MovementEventArgs(vector));
            }
        }

        protected void OnClick(Point location)
        {
            var local = Click;
            if (local != null)
            {
                local(this, new ClickEventArgs(location));
            }
        }

        protected void OnSlide()
        {
            var local = Slide;
            if (local != null)
            {
                local(this, new SlideEventArgs());
            }
        }

        protected void OnMouseDown(Point location)
        {
            var local = MouseDown;
            if (local != null)
            {
                local(this, new ClickEventArgs(location));
            }
        }

        protected void OnMouseUp(Point location)
        {
            var local = MouseUp;
            if (local != null)
            {
                local(this, new ClickEventArgs(location));
            }
        }
        #endregion

        private Point _downLocation;
        private Point _upLocation;
        private Point _lastLocation;
        private const int SlideDelta = 10;
        private InitialMovementArea _initialMovementArea;
        private Point _lastDelta;
        private bool _isMovement;

        private void MouseUpHandler(object sender, MouseEventArgs e)
        {
            this._upLocation = new Point(e.X, e.Y);

            if(this._isMovement == false)
            {
                Debug.WriteLine("Click");
                OnClick(this._upLocation);
            }
            else if (Math.Abs(this._lastDelta.X) > SlideDelta || Math.Abs(this._lastDelta.Y) > SlideDelta)
            {
                Debug.WriteLine("Slide");
                OnSlide();
            }

            OnMouseUp(this._upLocation);
            Debug.WriteLine("Up: " + this._upLocation.Print() + " | " + this._lastDelta.Print());
        }

        private void MouseMoveHandler(object sender, MouseEventArgs e)
        {
            var delta = new Point(e.X - this._lastLocation.X, e.Y - this._lastLocation.Y);
            if (delta == Point.Empty) return;

            this._lastDelta = delta;
            //Debug.WriteLine("Original Move: " + this._lastDelta.Print());

            this._initialMovementArea.RecordMovement(this._lastDelta);
            this._isMovement = this._initialMovementArea.IsMovement;
            if (this._isMovement == false)
            {
                return;
            }

            this._lastDelta = this._initialMovementArea.GetMovement();
            this._lastLocation = new Point(e.X, e.Y);
            this._initialMovementArea = new InitialMovementArea(this._lastLocation);

            OnMovement(this._lastDelta);

            Debug.WriteLine("Move: " + this._lastDelta.Print());
        }

        private void MouseDownHandler(object sender, MouseEventArgs e)
        {
            this._lastLocation = new Point(e.X, e.Y);
            this._downLocation = new Point(e.X, e.Y);
            this._initialMovementArea = new InitialMovementArea(this._downLocation);

            OnMouseDown(this._downLocation);
            //Debug.WriteLine("Down: " + this._downLocation.Print());
        }
    }
}